<?php


namespace models\Business;


use models\Exception\Business\CodeException;
use models\Exception\Business\MemberException;
use Yaf\Registry;
use youliPhpLib\Common\RequestHelper;
use youliPhpLib\Common\StringOperation;

class SmsCode
{
    const SMS_URL = "https://cdcxdxjk.market.alicloudapi.com/chuangxin/dxjk";
    const APP_CODE = "34bb256a03ce4caba2c79138272c6229";
    const APP_KEY = "203802317";
    const APP_SECRET = "f2b8pet9tjz0irzrl66o5rw7knb8m2kf";

    const ALLOWED_TYPE = ['login', 'register', 'resetpassword', 'bindalipay', 'bindmobile','paypassword', 'forgetPwd'];
    const LOGIN_SMS_TEMPLATE = "【飞扬众】登录验证码:#verification#，在5分钟内有效，请勿向第三方透露。";
//    const REGISTER_SMS_TEMPLATE = "【豆子有拼】注册验证码:#verification#，10分钟内有效，请勿向第三方透露。";
    const REGISTER_SMS_TEMPLATE = "【豆子优拼】注册验证码:#verification#，在5分钟内有效，请勿向第三方透露。";
    const ALIPAY_BIND_TEMPLATE = "【豆子优拼】验证码:#verification#，在5分钟内有效，请勿向第三方透露";

    /**
     * 生成短信验证码
     * @param $mobile
     * @param string $type
     * @return array|mixed
     * @throws CodeException
     * @throws MemberException
     */
    static public function genSmsCode($mobile, $type = 'register'){
        try {
            $mobile = !empty($mobile) && is_string($mobile) ? trim($mobile) : '';
            $type = !empty($type) && strpos('login,register,resetpassword,bindmobile,bindalipay,modifyalipay,paypassword,forgetPwd', $type) !== false ? $type : '';
            if (empty($mobile))
                throw new MemberException(MemberException::MEMBER_MOBILE_EMPTY, MemberException::MEMBER_MOBILE_EMPTY_NO);
            if (empty($type))
                throw new CodeException(CodeException::INVALID_TYPE, CodeException::INVALID_TYPE_NO);

            $cache_name = $type . ':' . $mobile;
            $data = Registry::get('redis_string')->getString($cache_name);
            if ($data) {
                $param = json_decode($data, true);
                $param['verification'] = StringOperation::getRandStr($type,6);
                Registry::get('redis_string')->updateString($cache_name, json_encode($param), $param['expire'] - time());
            } else {
                $expire = /*time() + */600;
                $param = [
                    'mobile' => $mobile,
                    'type' => $type,
                    'verification' => StringOperation::getRandStr($type, 6),
                    'expire' => time() + 600
                ];

                Registry::get('redis_string')->genString($cache_name, json_encode($param), $expire);
            }

            return $param;
        } catch (MemberException $e) {
            throw $e;
        } catch (CodeException $e) {
            throw $e;
        } catch (\Exception $e) {
            throw new MemberException(MemberException::GENERATE_SMS_CODE_FAILURE, MemberException::GENERATE_SMS_CODE_FAILURE_NO);
        }
    }

    /**
     * 验证短信验证码
     * @param $mobile
     * @param $code
     * @param string $type
     * @return bool
     * @throws MemberException
     */
    static public function verifySmsCode($mobile, $code, $type = 'register') {
        try {
            $mobile = !empty($mobile) && is_string($mobile) ? trim($mobile) : '';
            $type = !empty($type) && strpos('login,register,resetpassword,bindmobile,bindalipay,modifyalipay,paypassword,forgetPwd', $type) ? $type : '';
            if (empty($mobile))
                throw new MemberException(MemberException::MEMBER_MOBILE_EMPTY, MemberException::MEMBER_MOBILE_EMPTY_NO);

            $cache_name = $type . ':' . $mobile;
            $data = Registry::get('redis_string')->getString($cache_name);

            if (! $data)
                throw new MemberException(MemberException::THERE_IS_NO_SMS_CODE, MemberException::THERE_IS_NO_SMS_CODE_NO);

            $data = json_decode($data, true);
            if ($data['expire'] < time())
                throw new MemberException(MemberException::MEMBER_SMS_CODE_EXPIRE, MemberException::MEMBER_SMS_CODE_EXPIRE_NO);

            if ($data['verification'] != $code)
                throw new MemberException(MemberException::INVALID_SMS_CODE, MemberException::INVALID_SMS_CODE_NO);

            // 销毁
            Registry::get('redis_string')->deleteString($cache_name);

            return true;
        } catch (MemberException $e) {
            throw $e;
        }
    }

    static public function sendMessage($mobile, $content) {
        $headers = [
            'Authorization:APPCODE ' . self::APP_CODE
        ];

        /*if (! in_array($type, self::ALLOWED_TYPE))
            throw new CodeException(CodeException::INVALID_TYPE, CodeException::INVALID_TYPE_NO);
        if ($type == 'login')
            $content = str_replace("#verification#", "123456", self::LOGIN_SMS_TEMPLATE);
        else if ($type == 'register')
            $content = str_replace("#verification#", "123456", self::REGISTER_SMS_TEMPLATE);*/

        if (empty($content))
            throw new CodeException(CodeException::CONTENT_EMPTY, CodeException::CONTENT_EMPTY_NO);

        $param = [
            'content' => $content,
            'mobile' => $mobile
        ];

        $url = self::SMS_URL . '?' . http_build_query($param);

        list($resp_code, $header_size, $body) = RequestHelper::curlRequest($url, [], 'POST', $headers, false, 30, true);

        if ($resp_code != '200')
            throw new CodeException($body, $resp_code);

        $resp = substr($body, $header_size);
        Registry::get('sms_log')->info("接口调用参数:" . json_encode($param) . ",接口调用结果: " . $resp);

        $resp_arr = json_decode($resp, true);
        if ($resp_arr['ReturnStatus'] == 'Success' && $resp_arr['Message'] == 'ok')
            return true;

        throw new CodeException(CodeException::INVALID_RESP, CodeException::INVALID_RESP_NO);
    }
}
